import { Injectable, ExecutionContext } from '@nestjs/common';
import {
    CfsStorageDto,
    ClientDto,
    CntrSizeDto,
    CntrTypeDto,
    CyCfsAreaDto,
    CyCfsDto,
    PlaceDto,
    SCodeDto,
} from './dto/create-basedatum.dto';
import {
    DeleteDto,
    DeletePrimaryObjDto,
    DeleteStrPrimaryDto,
    ResponseJson,
    SqlQueryDto,
    UpdateDto,
} from '@/common/type/app.dto';
import {
    CfsStorageRate,
    Client,
    ClientBank,
    CntrSize,
    CntrType,
    CyCfs,
    CyCfsArea,
    Place,
    Scode,
} from './entities/basedatum.entity';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource, UpdateResult } from 'typeorm';
import { pinyin } from 'pinyin-pro';

import {
    QueryCfsStorageDto,
    UpdateCfsStroageDto,
    UpdateClientDto,
    UpdateCntrSizeDto,
    UpdateCntrTypeDto,
    UpdateCyCfsAreaDto,
    UpdateCyCfsDto,
    UpdatePlaceDto,
    UpdateSCodeDto,
} from './dto/update-basedatum.dto';
import { CrudService } from '@/shared/crud.service';
import { ResponseCode } from '@/common/type/enum';
import { isNil, omit } from 'lodash';
import { orderTree, OrderTree } from '@/common/tool/treehelper';

@Injectable()
export class BasedataService {
    constructor(
        @InjectDataSource() private datasource: DataSource,
        private crud: CrudService,
    ) { }

    async createCntrSize(
        cntrsize: CntrSizeDto,
    ): Promise<ResponseJson<CntrSize, null>> {
        return await this.crud.create<CntrSize, CntrSizeDto>(
            'CntrSize',
            cntrsize,
        );
    }
    async updateCntrSize(
        cntrsize: UpdateCntrSizeDto,
    ): Promise<ResponseJson<null, null>> {
        return await this.crud.update<CntrSize>('CntrSize', cntrsize, {
            cntr_siz_cod: cntrsize.primary_cod,
        });
    }
    async deleteCntrSizes(dto: DeleteStrPrimaryDto): Promise<ResponseJson> {
        return await this.crud.deleteStrIds<CntrSize>('CntrSize', dto);
    }
    async queryCntrSizes(
        query: SqlQueryDto,
    ): Promise<ResponseJson<CntrSize[], number>> {
        return await this.crud.query<CntrSize>('CntrSize', query);
    }
    async createDamCod(
        dto: SCodeDto,
    ): Promise<ResponseJson<Scode, null>> {
        dto.fld_eng = 'DAM_ID';
        dto.fld_chi = '箱好坏';
        dto.name = dto.code;
        return await this.crud.create<Scode, SCodeDto>(
            'Scode',
            dto,
        );
    }
    async updateDamCod(
        dto: UpdateSCodeDto,
    ): Promise<ResponseJson<null, null>> {
        dto.fld_eng = 'DAM_ID';
        dto.fld_chi = '箱好坏';
        dto.name = dto.code;
        return await this.crud.update<Scode>('Scode', dto, {
            fld_eng: 'DAM_ID',
            code: dto.primary_cod.code
        });
        
    }
    async deleteDamCod(dto: DeletePrimaryObjDto): Promise<ResponseJson> {
        return await this.crud.deleteObjIds<Scode>('Scode', dto);
    }
    async queryDamCod(
        query: SqlQueryDto,
    ): Promise<ResponseJson<Scode[], number>> {
        query.where = {
            fld_eng: {
                equals: 'DAM_ID'
            }
        }
        return await this.crud.query<Scode>('Scode', query);
    }
    async createCntrType(
        cntrtype: CntrTypeDto,
    ): Promise<ResponseJson<CntrType, null>> {
        return await this.crud.create<CntrType, CntrTypeDto>(
            CntrType,
            cntrtype,
        );
    }
    async updateCntrType(
        cntrtype: UpdateCntrTypeDto,
    ): Promise<ResponseJson<null, null>> {
        return await this.crud.update<CntrType>(CntrType, cntrtype, {
            cntr_typ_cod: cntrtype.primary_cod,
        });
    }
    async deleteCntrTypes(dto: DeleteStrPrimaryDto): Promise<ResponseJson> {
        return await this.crud.deleteStrIds<CntrType>(CntrType, dto);
    }
    async queryCntrTypes(
        query: SqlQueryDto,
    ): Promise<ResponseJson<CntrType[], number>> {
        return await this.crud.query<CntrType>(CntrType, query);
    }
    async createCyCfs(dto: CyCfsDto): Promise<ResponseJson<CyCfs, null>> {
        // return await this.crud.create<CyCfs, CyCfsDto>(CyCfs, dto);
        const cfsObj = this.datasource.manager.create<CyCfs>(CyCfs, dto);
        /* if (!isNil(dto.parentId)) {
            const parent = await this.datasource.manager.findOne<CyCfs>(CyCfs, {
                where: {
                    id: dto.parentId,
                },
            });
            cfsObj.parent = parent;
        } */
        const r = await this.datasource.manager.save<CyCfs>(cfsObj);
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: r,
        };
    }
    async updateCyCfs(dto: UpdateCyCfsDto): Promise<ResponseJson<null, null>> {
        /* const parent = isNil(dto.parentId)
            ? null
            : await this.datasource.manager.findOne<CyCfs>(CyCfs, {
                where: {
                    id: dto.parentId,
                },
            }); */
        const oldCyCfs = await this.datasource.manager.preload<CyCfs>(
            CyCfs,
            omit(dto, ['parentId']),
        );
        // oldCyCfs.parent = parent;
        const r = await this.datasource.manager.save<CyCfs>(oldCyCfs);
        return {
            code: ResponseCode.SuccessWithSuc,
            msg: ['修改成功'],
        };
    }
    async deleteCyCfs(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<CyCfs>(CyCfs, dto);
    }
    async queryCyCfs(query: SqlQueryDto) /* query: SqlQueryDto, */
        : Promise<ResponseJson<CyCfs[], number>> {
        return await this.crud.query<CyCfs>(CyCfs, query);
    }
    async createStroageRate(dto: CfsStorageDto): Promise<ResponseJson<CfsStorageRate, null>> {
        return this.crud.create<CfsStorageRate, CfsStorageDto>(CfsStorageRate, dto);
    }
    async updateStroageRate(dto: UpdateCfsStroageDto): Promise<ResponseJson<CfsStorageRate, null>> {
        return this.crud.update(CfsStorageRate, dto);
    }
    async deleteStroageRate(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<CfsStorageRate>(CfsStorageRate, dto);
    }
    async queryStroageRate(dto: QueryCfsStorageDto): Promise<ResponseJson<CfsStorageRate[], null>> {
        const r = await this.datasource.manager.createQueryBuilder<CfsStorageRate>(CfsStorageRate, 'c_cfs_storage_rate')
        .where('cfs_cod = :cfs_cod', { cfs_cod: dto.cfs_id})
        .getMany();
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: r
        }
    }

    async createCyCfsArea(
        dto: CyCfsAreaDto,
    ): Promise<ResponseJson<CyCfsArea, null>> {
        const cfs = await this.datasource
            .createQueryBuilder()
            .select('c_cy_cfs')
            .from<CyCfs>(CyCfs, 'c_cy_cfs')
            .where('cfs_cod = :cfs_cod', { cfs_cod: dto.cfs_cod })
            .getOne();
        if (isNil(cfs)) {
            return {
                code: ResponseCode.FailWithMsg,
                msg: ['非法站点'],
            };
        }
        return await this.crud.create<CyCfsArea, CyCfsAreaDto>(CyCfsArea, dto);
    }
    async updateCyCfsArea(
        dto: UpdateCyCfsAreaDto,
    ): Promise<ResponseJson<null, null>> {
        const cfs = await this.datasource
            .createQueryBuilder()
            .select('c_cy_cfs')
            .from<CyCfs>(CyCfs, 'c_cy_cfs')
            .where('cfs_cod = :cfs_cod', { cfs_cod: dto.cfs_cod })
            .getOne();
        if (isNil(cfs)) {
            return {
                code: ResponseCode.FailWithMsg,
                msg: ['非法站点'],
            };
        }
        return await this.crud.update<CyCfsArea>(CyCfsArea, dto, {
            cfs_cod: dto.primary_cod.cfs_cod,
            cy_area: dto.primary_cod.cy_area,
        });
    }
    async deleteCyCfsArea(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<CyCfsArea>(CyCfsArea, dto);
    }
    async queryCyCfsArea(
        query: SqlQueryDto,
    ): Promise<ResponseJson<CyCfsArea[], number>> {
        return await this.crud.query<CyCfsArea>(CyCfsArea, query);
    }
    async createClient(dto: ClientDto): Promise<ResponseJson<Client, null>> {
        if (dto.client_nam_c) {
            dto.client_nam_index = pinyin(dto.client_nam_c, {
                pattern: 'first',
                toneType: 'none',
                type: 'string',
                separator: '',
            });
        }
        const banks = dto.banks;
        const client = omit(dto, ['banks']);

        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const insertClientResult = await queryRunner.manager
                .createQueryBuilder()
                .insert()
                .into(Client)
                .values(client)
                .execute();
            const client_id = insertClientResult.identifiers[0]['id'];
            if (!isNil(banks)) {
                banks.forEach((bank) => {
                    bank.client_id = client_id;
                });

                await queryRunner.manager
                    .createQueryBuilder()
                    .insert()
                    .into(ClientBank)
                    .values(banks)
                    .execute();
            }
            const newClient = await queryRunner.manager.createQueryBuilder<Client>(Client, 'c_client_cod')
            .leftJoinAndSelect('c_client_cod.banks','c_client_bank')
            .where('c_client_cod.id = :id', {id: client_id})
            .getOne();
            await queryRunner.commitTransaction();
            return {
                code: ResponseCode.SuccessWithInfo,
                obj: newClient,
                msg: ['创建成功'],
            };
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async updateClient(
        dto: UpdateClientDto,
    ): Promise<ResponseJson<null, null>> {
        if (dto.client_nam_c) {
            dto.client_nam_index = pinyin(dto.client_nam_c, {
                pattern: 'first',
                toneType: 'none',
                type: 'string',
                separator: '',
            });
        }
        const banks = dto.banks;
        const client = omit(dto, ['banks']);


        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const updateClientResult: UpdateResult = await queryRunner.manager.createQueryBuilder().update(Client)
                .set(client).where('id = :id', { id: dto['id'] }).execute();
            if (updateClientResult.affected != 1) {
                throw new Error("无此客户，修改失败");
            }
            await queryRunner.manager.createQueryBuilder().delete().from(ClientBank)
                .where('client_id = :id', { id: dto['id'] }).execute();
            if (!isNil(banks)) {
                banks.forEach((bank) => {
                    bank.client_id = dto['id'];
                });

                await queryRunner.manager
                    .createQueryBuilder()
                    .insert()
                    .into(ClientBank)
                    .values(banks)
                    .execute();
            }
            await queryRunner.commitTransaction();
            return {
                code: ResponseCode.SuccessWithInfo,
                msg: ['修改成功'],
            };
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
        // return await this.crud.update<Client>(Client, dto);
    }
    async deleteClient(dto: DeleteDto): Promise<ResponseJson> {

        return await this.crud.delete<Client>(Client, dto);
    }
    async queryClient(
        query: SqlQueryDto,
    ): Promise<ResponseJson<Client[], number>> {
        query.left = [
            {
                property: 'c_client_cod.banks',
                alias: 'c_client_bank',
            },
        ];
        /* const r = await this.datasource.createQueryBuilder<Client>(Client, 'c_client_cod').
        
        leftJoinAndSelect('c_client_cod.banks','c_client_bank', 'c_client_cod.id = c_client_bank.client_id').
        where('c_client_cod.client_nam_c = :name', {name: '田敏'}).getManyAndCount(); */

        return await this.crud.query<Client>(Client, query);

    }
    async createPlace(dto: PlaceDto): Promise<ResponseJson<Place, null>> {
        return await this.crud.create<Place, PlaceDto>(Place, dto);
    }
    async updatePlace(dto: UpdatePlaceDto): Promise<ResponseJson<null, null>> {
        return await this.crud.update<Place>(Place, dto);
    }
    async deletePlace(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<Place>(Place, dto);
    }
    async queryPlace(
        query: SqlQueryDto,
    ): Promise<ResponseJson<Place[], number>> {
        return await this.crud.query<Place>(Place, query);
    }
}
